/*
 * Reads lexical config files and updates database.
 *
 * MUSCLE SmartCard Development ( http://www.linuxnet.com )
 *
 * Copyright (C) 2001-2003
 *  David Corcoran <corcoran@linuxnet.com>
 * Copyright (C) 2003-2010
 *  Ludovic Rousseau <ludovic.rousseau@free.fr>
 *
 * $Id: tokenparser.l 6325 2012-06-06 11:54:48Z rousseau $
 */

/**
 * @file
 * @brief provides parsing functions for Info.plist files
 * platforms
 */

%{

#include "config.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#define NDEBUG
#include <assert.h>

#include "simclist.h"
#include "debuglog.h"
#include "parser.h"
#include "strlcpycat.h"

static void eval_key(char *pcToken, list_t *list_key);
static void eval_value(char *pcToken, list_t *list_values);
void tperrorCheck (char *pcToken_error);

static list_t *ListKeys;
static list_t *ListValues;

%}

%option nounput
%option noinput
%option noyywrap

%%

#.*                                             {}
"\n"                                            {}
\<key\>([A-Z]|[a-z]|[0-9]|[ \t])+\<\/key\>      { eval_key(yytext, ListKeys); }
[ \t]                                           {}
\<string\>([A-Z]|[a-z]|[0-9]|[ \t]|[!@#$%^&*()\-+/_\:?.,=~'";\[\]])+\<\/string\> { eval_value(yytext, ListValues); }
.                                               { tperrorCheck(yytext); }
%%


static void eval_key(char *pcToken, list_t *list_key)
{
	struct bundleElt *elt;
	int r;
	size_t len;

	/* create a new list element */
	elt = malloc(sizeof(*elt));
	assert(elt);

	/* <key>foobar</key>
	 * 012345 : 5 is the first key character index */

	/* calculate the argument length */
	for (len=0; pcToken[len+5] != '<'; len++)
		;
	len++;	/* final NULL byte */

	elt->key = malloc(len);
	(void)strlcpy(elt->key, &pcToken[5], len);

	r = list_init(&elt->values);
	assert(r >= 0);
	(void)r;

	/* add the key/values */
	list_append(list_key, elt);

	/* set the list to store the values */
	ListValues = &elt->values;
}

static void eval_value(char *pcToken, list_t *list_values)
{
	int r;
	size_t len;
	char *value;
	char *amp;

	/* <string>foobar</string>
	 * 012345678 : 8 is the first string character index */

	/* calculate the argument length */
	for (len=0; pcToken[len+8] != '<'; len++)
		;
	len++;	/* final NULL byte */

	value = malloc(len);
	assert(value);

	(void)strlcpy(value, &pcToken[8], len);

	/* convert the firt &amp; into & */
	amp = strstr(value, "&amp;");
	if (amp)
	{
		char *p;

		/* just skip "amp;" substring (4 letters) */
		for (p = amp+1; *(p+4); p++)
		{
			*p = *(p+4);
		}
	}

	r = list_append(list_values, value);
	assert(r >= 0);
	(void)r;
}

void tperrorCheck (char *token_error)
{
    (void)token_error;
}

/**
 * Find an optional key in a configuration file
 * No error is logged if the key is not found
 *
 * @param l list generated by bundleParse()
 * @param key searched key
 * @param[out] values list of token value (if key found)
 * @retval 0 OK
 * @retval 1 key not found
 */
int LTPBundleFindValueWithKey(list_t *l, const char *key, list_t **values)
{
	unsigned int i;
	int ret = 1;

	for (i=0; i < list_size(l); i++)
	{
		struct bundleElt *elt;

		elt = list_get_at(l, i);
		assert(elt);

		if (0 == strcmp(elt->key, key))
		{
			*values = &elt->values;
			ret = 0;
		}
	}

	return ret;
}


/**
 * Parse a Info.plist file and file a list
 *
 * @param fileName file name
 * @param l list containing the results
 * @retval -1 configuration file not found
 * @retval 0 OK
 */
int bundleParse(const char *fileName, list_t *l)
{
	FILE *file = NULL;
	int r;
#ifndef NDEBUG
	int i;
#endif

	file = fopen(fileName, "r");
	if (!file)
	{
		Log3(PCSC_LOG_CRITICAL, "Could not open bundle file %s: %s",
			fileName, strerror(errno));
		return 1;
	}

	r = list_init(l);
	assert(r >= 0);
	(void)r;

	ListKeys = l;
	yyin = file;

	do
	{
		(void)yylex();
	} while (!feof(file));

	(void)fclose(file);

#ifndef NDEBUG
	printf("size: %d\n", list_size(l));
	for (i=0; i < list_size(l); i++)
	{
		struct bundleElt *elt;
		unsigned int j;

		elt = list_get_at(l, i);
		assert(elt);
		printf("Key: %s\n", elt->key);

		for (j=0; j<list_size(&elt->values); j++)
		{
			char *v = list_get_at(&elt->values, j);
			printf(" value: %s\n", v);
		}
	}
#endif

	return 0;
}

/**
 * Free the list created by bundleParse()
 *
 * @param l list containing the results
 */
void bundleRelease(list_t *l)
{
	unsigned int i;

	for (i=0; i < list_size(l); i++)
	{
		struct bundleElt *elt;
		unsigned int j;

		elt = list_get_at(l, i);
		assert(elt);

		/* free all the values */
		for (j=0; j<list_size(&elt->values); j++)
			free(list_get_at(&elt->values, j));
		list_destroy(&elt->values);

		/* free the key */
		free(elt->key);
		free(elt);
	}

	list_destroy(l);
}
